﻿#include "ssShaderManager.h"
#include <string.h>
//#include <stdio.h>
//#include <fcntl.h>
#include "tools/ssProcessInfo.h"


namespace StarSeeker
{

SS_SINGLETON_INIT(ssShaderManager)

ssShaderManager::ssShaderManager()
{
}

ssShaderManager::~ssShaderManager()
{
	Clear();
}

bool ssShaderManager::AddShader( ssShader* ps )
{
	if (!ps || ps->Name().Length()==0 || !ps->LinkShader())
	{
		return false;
	}
	ssPair<ssMap<ulint, ssShader*>::Iterator, error_t> ret = m_mapShader.Insert(ps->HashNum(), ps);
	if (ret.second==0)
	{
		ret.first.Second()->Use();
		return true;
	}
	else
	{
		return false;
	}
}

bool ssShaderManager::DeleteShader( const char* name )
{
	if (name)
	{
		ulint hash = DJBHashCode(name, strlen(name));
		return DeleteShader(hash);
	}
	return false;
}

bool ssShaderManager::DeleteShader(ulint hash)
{
	ssMap<ulint, ssShader*>::Iterator itr = m_mapShader.Find(hash);
	if (itr.IsVaild())
	{
		itr.Second()->Unload();
		delete itr.Second();
		m_mapShader.Erase(itr);
		return true;
	}
	return false;
}

ssShader* ssShaderManager::Find( const char* name )
{
	if (name)
	{
		ulint hash = DJBHashCode(name, strlen(name));
		return Find(hash);
	}
	return 0;
}

ssShader* ssShaderManager::Find( ulint hash )
{
	ssMap<ulint, ssShader*>::Iterator itr = m_mapShader.Find(hash);
	if (itr.IsVaild())
	{
		return itr.Second();
	}
	return 0;
}

void ssShaderManager::Clear()
{
	ssMap<ulint, ssShader*>::Iterator itr = m_mapShader.Begin();
	while (itr.IsVaild())
	{
		itr.Second()->Unload();
		delete itr.Second();
		++itr;
	}
	m_mapShader.Empty();
}

void ssShaderManager::CreateDefaultShader()
{
	std::string vs,ps;

	ssShader* ps2 = new ssShader("test");
	const char* glslv2 = "attribute vec3 inPosition;void main(){gl_Position=vec4(inPosition, 1.0);}";
	const char* glslp2 = "void main(){gl_FragColor=vec4(1.0, 1.0, 0.0, 1.0);}";
	if (ps2->CompileVertexShader(glslv2, strlen(glslv2)) && ps2->CompilePiexlShader(glslp2, strlen(glslp2)))
	{
		AddShader(ps2);
	}

	ssShader* ps3 = new ssShader("camera_test");
	const char* glslv3 = "attribute vec3 inPosition;\
uniform mat4 inProjMat;\
uniform mat4 inViewMat;\
void main(){gl_Position=inProjMat*inViewMat*vec4(inPosition, 1.0);}";
	const char* glslp3 = "void main(){gl_FragColor=vec4(0.0, 1.0, 1.0, 1.0);}";
	if (ps3->CompileVertexShader(glslv3, strlen(glslv3)) && ps3->CompilePiexlShader(glslp3, strlen(glslp3)))
	{
		AddShader(ps3);
	}

	ssShader* ps4 = new ssShader("base");
	vs = SS_GET_RES_PATH("shader/base.vs");
	ps = SS_GET_RES_PATH("shader/base.ps");
	if (ps4->CompileVertexShaderFromFile(vs.c_str()) && ps4->CompilePiexlShaderFromFile(ps.c_str()))
	{
		AddShader(ps4);
	}

	ssShader* ps5 = new ssShader("color");
	vs = SS_GET_RES_PATH("shader/color.vs");
	ps = SS_GET_RES_PATH("shader/color.ps");
	if (ps5->CompileVertexShaderFromFile(vs.c_str()) && ps5->CompilePiexlShaderFromFile(ps.c_str()))
	{
		AddShader(ps5);
	}

	ssShader* ps1 = new ssShader("texture2d");
	vs = SS_GET_RES_PATH("shader/texture2d.vs");
	ps = SS_GET_RES_PATH("shader/texture2d.ps");
	if (ps1->CompileVertexShaderFromFile(vs.c_str()) && ps1->CompilePiexlShaderFromFile(ps.c_str()))
	{
		AddShader(ps1);
	}

#ifndef SS_USE_GLES2
	ssShader* ps6 = new ssShader("terrain1.0");
	vs = SS_GET_RES_PATH("shader/terrain1.0.vs");
	ps = SS_GET_RES_PATH("shader/terrain1.0.ps");
	if (ps6->CompileVertexShaderFromFile(vs.c_str()) && ps6->CompilePiexlShaderFromFile(ps.c_str()))
	{
		AddShader(ps6);
	}
#endif

	ssShader* ps7 = new ssShader("vlighting");
	vs = SS_GET_RES_PATH("shader/vlighting.vs");
	ps = SS_GET_RES_PATH("shader/color.ps");
	if (ps7->CompileVertexShaderFromFile(vs.c_str()) && ps7->CompilePiexlShaderFromFile(ps.c_str()))
	{
		AddShader(ps7);
	}

	ssShader* ps8 = new ssShader("vlightingTex");
	vs = SS_GET_RES_PATH("shader/vlightingTex.vs");
	ps = SS_GET_RES_PATH("shader/vlightingTex.ps");
	if (ps8->CompileVertexShaderFromFile(vs.c_str()) && ps8->CompilePiexlShaderFromFile(ps.c_str()))
	{
		AddShader(ps8);
	}

	ssShader* ps9 = new ssShader("plighting");
	vs = SS_GET_RES_PATH("shader/plighting.vs");
	ps = SS_GET_RES_PATH("shader/plighting.ps");
	if (ps9->CompileVertexShaderFromFile(vs.c_str()) && ps9->CompilePiexlShaderFromFile(ps.c_str()))
	{
		AddShader(ps9);
	}

	ssShader::NonuseShader();
}

}
